package com.thx.common.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;

import javax.imageio.ImageIO;

/**
 * 图片工具类. 此文件代码重复量太大, 同样代码重复有4处, 建议重构 : (
 */
public class ImgUtil {

  private int width; // 原图片宽度

  private int scaleWidth; // 转换过程中没有补白前临时图片的宽度

  private static final double support = (double) 3.0;

  private static final double PI = (double) 3.14159265358978;

  private double[] contrib;

  private double[] normContrib;

  private double[] tmpContrib;

  // int startContrib, stopContrib;

  private int dots;

  private int halfDots;

  public ImgUtil() {

  }

  /**
   * 按新的宽度等比缩放图片.
   */
  public void resizeImgToJpegByWidth(String src, String toImg, int newWidth) throws Exception {
    File srcImg = new File(src);
    BufferedImage bufImage = javax.imageio.ImageIO.read(srcImg); // construct image
    resizeImgToJpegByWidth(bufImage, toImg, newWidth);
  }

  /**
   * 按新的宽度等比缩放图片.
   */
  public void resizeImgToJpegByWidth(BufferedImage bufImgSrcImg, String toImg, int newWidth)
      throws Exception {
    File fileToImg = new File(toImg);
    int orginalWidth = bufImgSrcImg.getWidth(null);
    int orginalHeight = bufImgSrcImg.getHeight(null);

    // 默认不做放大处理
    int tmpWidth = orginalWidth;
    int tmpHeight = orginalHeight;

    if (orginalWidth > 0 && orginalHeight > 0) {

      tmpWidth = newWidth;
      tmpHeight = (orginalHeight * newWidth) / orginalWidth;
    }

    bufImgSrcImg = imageZoomOut(bufImgSrcImg, tmpWidth, tmpHeight);
    ImageIO.write(bufImgSrcImg, "JPEG", fileToImg);
  }


  /**
   * 按新的高度等比缩放图片.
   */
  public void resizeImgToJpegByHeight(String srcImg, String toImg, int newHeight) throws Exception {
    File fileSrcImg = new File(srcImg);
    BufferedImage bufImgSrcImg = javax.imageio.ImageIO.read(fileSrcImg); // construct image
    resizeImgToJpegByHeight(bufImgSrcImg, toImg, newHeight);
  }

  /**
   * 按新的高度等比缩放图片.
   */
  public void resizeImgToJpegByHeight(BufferedImage bufImgSrcImg, String toImg, int newHeight)
      throws Exception {
    File fileToImg = new File(toImg);
    int orginalWidth = bufImgSrcImg.getWidth(null);
    int orginalHeight = bufImgSrcImg.getHeight(null);

    // 默认不做放大处理
    int tmpWidth = orginalWidth;
    int tmpHeight = orginalHeight;

    if (orginalWidth > 0 && orginalHeight > 0) {

      tmpHeight = newHeight;
      tmpWidth = (orginalWidth * newHeight) / orginalHeight;
    }

    bufImgSrcImg = imageZoomOut(bufImgSrcImg, tmpWidth, tmpHeight);
    ImageIO.write(bufImgSrcImg, "JPEG", fileToImg);
  }

  /**
   * 按图片原来的长宽比生成缩放图片，不足的地方补白.
   *
   * @param srcImg 原图片路径
   * @param toImg 目标图片路径
   * @param newWidth 新图片宽
   * @param newHeight 新图片高
   */
  public void resizeImgToJpeg(String srcImg, String toImg, int newWidth, int newHeight)
      throws Exception {
    File fileSrcImg = new File(srcImg);
    BufferedImage bufImgSrcImg = javax.imageio.ImageIO.read(fileSrcImg); // construct image
    int orginalWidth = bufImgSrcImg.getWidth(null);
    int orginalHeight = bufImgSrcImg.getHeight(null);

    // 默认不做放大处理
    int tmpWidth = orginalWidth;
    int tmpHeight = orginalHeight;

    if (orginalWidth > 0 && orginalHeight > 0) {
      // 等比例缩放
      if (orginalWidth / orginalHeight >= newWidth / newHeight) {
        // 宽度优先
        if (orginalWidth > newWidth) { // 缩小
          tmpWidth = newWidth;
          tmpHeight = (orginalHeight * newWidth) / orginalWidth;
        }
      } else {
        // 高度优先
        if (orginalHeight > newHeight) {
          tmpHeight = newHeight;
          tmpWidth = (orginalWidth * newHeight) / orginalHeight;
        }
      }
    }

    bufImgSrcImg = imageZoomOut(bufImgSrcImg, tmpWidth, tmpHeight);

    // 补白

    BufferedImage image = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
    Graphics2D graphics = image.createGraphics();
    graphics.setColor(Color.white);
    graphics.fillRect(0, 0, newWidth, newHeight);
    if (newWidth == bufImgSrcImg.getWidth(null)) {
      graphics.drawImage(bufImgSrcImg, 0, (newHeight - bufImgSrcImg.getHeight(null)) / 2,
          bufImgSrcImg.getWidth(null), bufImgSrcImg.getHeight(null), Color.white, null);
    } else {
      graphics.drawImage(bufImgSrcImg, (newWidth - bufImgSrcImg.getWidth(null)) / 2, 0,
          bufImgSrcImg.getWidth(null), bufImgSrcImg.getHeight(null), Color.white, null);
    }
    graphics.dispose();
    bufImgSrcImg = image;

    File fileToImg = new File(toImg);
    ImageIO.write(bufImgSrcImg, "JPEG", fileToImg);
  }

  /**
   * 按图片原来的长宽比生成缩放图片，不足的地方补白.
   */
  public void resizeImgToJpeg(BufferedImage bufImgSrcImg, File fileToImg, int newWidth,
      int newHeight) throws Exception {

    // File fToImg = new File(toImg);
    // File fSrcImg = new File(srcImg);
    // BufferedImage bImgSrcImg = javax.imageio.ImageIO.read(fSrcImg); // construct image
    int orginalWidth = bufImgSrcImg.getWidth(null);
    int orginalHeight = bufImgSrcImg.getHeight(null);

    // 默认不做放大处理
    int tmpWidth = orginalWidth;
    int tmpHeight = orginalHeight;

    if (orginalWidth > 0 && orginalHeight > 0) {
      // 等比例缩放
      if (orginalWidth / orginalHeight >= newWidth / newHeight) {
        // 宽度优先
        if (orginalWidth > newWidth) { // 缩小
          tmpWidth = newWidth;
          tmpHeight = (orginalHeight * newWidth) / orginalWidth;
        }
      } else {
        // 高度优先
        if (orginalHeight > newHeight) {
          tmpHeight = newHeight;
          tmpWidth = (orginalWidth * newHeight) / orginalHeight;
        }
      }
    }

    bufImgSrcImg = imageZoomOut(bufImgSrcImg, tmpWidth, tmpHeight);

    // 补白

    BufferedImage image = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
    Graphics2D graphics = image.createGraphics();
    graphics.setColor(Color.white);
    graphics.fillRect(0, 0, newWidth, newHeight);
    if (newWidth == bufImgSrcImg.getWidth(null)) {
      graphics.drawImage(bufImgSrcImg, 0, (newHeight - bufImgSrcImg.getHeight(null)) / 2,
          bufImgSrcImg.getWidth(null), bufImgSrcImg.getHeight(null), Color.white, null);
    } else {
      graphics.drawImage(bufImgSrcImg, (newWidth - bufImgSrcImg.getWidth(null)) / 2, 0,
          bufImgSrcImg.getWidth(null), bufImgSrcImg.getHeight(null), Color.white, null);
    }
    graphics.dispose();
    bufImgSrcImg = image;

    ImageIO.write(bufImgSrcImg, "JPEG", fileToImg);
  }


  /**
   * 按图片原来的长宽比生成缩放图片，不足的地方补白,根据参数来确定是否补白.
   *
   * @param srcImg 原图片路径
   * @param toImg 目标图片路径
   * @param newWidth 新图片宽
   * @param newHeight 新图片高
   */
  public void resizeImgToJpeg(String srcImg, String toImg, int newWidth, int newHeight,
      boolean needFiller) throws Exception {
    File fileSrcImg = new File(srcImg);
    BufferedImage bufImgSrcImg = javax.imageio.ImageIO.read(fileSrcImg); // construct image
    int orginalWidth = bufImgSrcImg.getWidth(null);
    int orginalHeight = bufImgSrcImg.getHeight(null);

    // 默认不做放大处理
    int tmpWidth = orginalWidth;
    int tmpHeight = orginalHeight;

    if (orginalWidth > 0 && orginalHeight > 0) {
      // 等比例缩放
      if (orginalWidth / orginalHeight >= newWidth / newHeight) {
        // 宽度优先
        if (orginalWidth > newWidth) { // 缩小
          tmpWidth = newWidth;
          tmpHeight = (orginalHeight * newWidth) / orginalWidth;
        }
      } else {
        // 高度优先
        if (orginalHeight > newHeight) {
          tmpHeight = newHeight;
          tmpWidth = (orginalWidth * newHeight) / orginalHeight;
        }
      }
    }

    bufImgSrcImg = imageZoomOut(bufImgSrcImg, tmpWidth, tmpHeight);

    // 补白
    if (needFiller) {
      BufferedImage image = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
      Graphics2D graphics = image.createGraphics();
      graphics.setColor(Color.white);
      graphics.fillRect(0, 0, newWidth, newHeight);
      if (newWidth == bufImgSrcImg.getWidth(null)) {
        graphics.drawImage(bufImgSrcImg, 0, (newHeight - bufImgSrcImg.getHeight(null)) / 2,
            bufImgSrcImg.getWidth(null), bufImgSrcImg.getHeight(null), Color.white, null);
      } else {
        graphics.drawImage(bufImgSrcImg, (newWidth - bufImgSrcImg.getWidth(null)) / 2, 0,
            bufImgSrcImg.getWidth(null), bufImgSrcImg.getHeight(null), Color.white, null);
      }
      graphics.dispose();
      bufImgSrcImg = image;
    }

    File fileToImg = new File(toImg);
    ImageIO.write(bufImgSrcImg, "JPEG", fileToImg);
  }

  /**
   * 按图片原来的长宽比生成缩放图片，不足的地方补白,根据参数来确定是否补白.
   */
  public void resizeImgToJpeg(InputStream is, File fileToImg, int newWidth, int newHeight,
      boolean needFiller) throws Exception {

    // File fToImg = new File(toImg);
    // File fSrcImg = new File(srcImg);
    BufferedImage bufImgSrcImg = javax.imageio.ImageIO.read(is); // construct image
    int orginalWidth = bufImgSrcImg.getWidth(null);
    int orginalHeight = bufImgSrcImg.getHeight(null);

    // 默认不做放大处理
    int tmpWidth = orginalWidth;
    int tmpHeight = orginalHeight;

    if (orginalWidth > 0 && orginalHeight > 0) {
      // 等比例缩放
      if (orginalWidth / orginalHeight >= newWidth / newHeight) {
        // 宽度优先
        if (orginalWidth > newWidth) { // 缩小
          tmpWidth = newWidth;
          tmpHeight = (orginalHeight * newWidth) / orginalWidth;
        }
      } else {
        // 高度优先
        if (orginalHeight > newHeight) {
          tmpHeight = newHeight;
          tmpWidth = (orginalWidth * newHeight) / orginalHeight;
        }
      }
    }

    bufImgSrcImg = imageZoomOut(bufImgSrcImg, tmpWidth, tmpHeight);

    // 补白

    if (needFiller) {
      BufferedImage image = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
      Graphics2D graphics = image.createGraphics();
      graphics.setColor(Color.white);
      graphics.fillRect(0, 0, newWidth, newHeight);
      if (newWidth == bufImgSrcImg.getWidth(null)) {
        graphics.drawImage(bufImgSrcImg, 0, (newHeight - bufImgSrcImg.getHeight(null)) / 2,
            bufImgSrcImg.getWidth(null), bufImgSrcImg.getHeight(null), Color.white, null);
      } else {
        graphics.drawImage(bufImgSrcImg, (newWidth - bufImgSrcImg.getWidth(null)) / 2, 0,
            bufImgSrcImg.getWidth(null), bufImgSrcImg.getHeight(null), Color.white, null);
      }
      graphics.dispose();
      bufImgSrcImg = image;
    }
    ImageIO.write(bufImgSrcImg, "JPEG", fileToImg);
  }


  /**
   * 图片缩放.
   */
  public BufferedImage imageZoomOut(BufferedImage srcBufferImage, int tmpWidth, int tmpHeight) {
    width = srcBufferImage.getWidth();

    scaleWidth = tmpWidth;

    calContrib();
    BufferedImage pbOut = horizontalFiltering(srcBufferImage, tmpWidth);
    BufferedImage pbFinalOut = verticalFiltering(pbOut, tmpHeight);
    return pbFinalOut;
  }

  private double lanczos(int index, int inWidth, int outWidth, double support) {
    double theX = (double) index * (double) outWidth / (double) inWidth;
    return Math.sin(theX * PI) / (theX * PI) * Math.sin(theX * PI / support)
        / (theX * PI / support);

  }

  private void calContrib() {
    halfDots = (int) ((double) width * support / (double) scaleWidth);
    dots = halfDots * 2 + 1;
    try {
      contrib = new double[dots];
      normContrib = new double[dots];
      tmpContrib = new double[dots];
    } catch (Exception ex) {
      System.out.println("init   contrib,normContrib,tmpContrib" + ex);
    }

    int center = halfDots;
    contrib[center] = 1.0;

    double weight = 0.0;
    for (int i = 1; i <= center; i++) {
      contrib[center + i] = lanczos(i, width, scaleWidth, support);
      weight += contrib[center + i];
    }

    for (int i = center - 1; i >= 0; i--) {
      contrib[i] = contrib[center * 2 - i];
    }

    weight = weight * 2 + 1.0;

    for (int i = 0; i <= center; i++) {
      normContrib[i] = contrib[i] / weight;
    }

    for (int i = center + 1; i < dots; i++) {
      normContrib[i] = normContrib[center * 2 - i];
    }
  } // end of calContrib()

  // 处理边缘
  private void calTempContrib(int start, int stop) {
    double weight = 0;

    for (int i = start; i <= stop; i++) {
      weight += contrib[i];
    }
    for (int i = start; i <= stop; i++) {
      tmpContrib[i] = contrib[i] / weight;
    }
  }

  private int getRedValue(int rgbValue) {
    int temp = rgbValue & 0x00ff0000;
    return temp >> 16;
  }

  private int getGreenValue(int rgbValue) {
    int temp = rgbValue & 0x0000ff00;
    return temp >> 8;
  }

  private int getBlueValue(int rgbValue) {
    return rgbValue & 0x000000ff;
  }

  private int comRgb(int redValue, int greenValue, int blueValue) {

    return (redValue << 16) + (greenValue << 8) + blueValue;
  }

  // 行水平滤波
  private int horizontalFilter(BufferedImage bufImg, int startX, int stopX, int start, int stop,
      int theY, double[] pointContrib) {
    double valueRed = 0.0;
    double valueGreen = 0.0;
    double valueBlue = 0.0;
    int valueRgb = 0;

    for (int i = startX, j = start; i <= stopX; i++, j++) {
      valueRgb = bufImg.getRGB(i, theY);

      valueRed += getRedValue(valueRgb) * pointContrib[j];
      valueGreen += getGreenValue(valueRgb) * pointContrib[j];
      valueBlue += getBlueValue(valueRgb) * pointContrib[j];
    }

    valueRgb = comRgb(clip((int) valueRed), clip((int) valueGreen), clip((int) valueBlue));
    return valueRgb;

  } // end of horizontalFilter()

  // 图片水平滤波
  private BufferedImage horizontalFiltering(BufferedImage bufImage, int outWith) {
    int dwInW = bufImage.getWidth();
    int dwInH = bufImage.getHeight();
    int value = 0;
    BufferedImage pbOut = new BufferedImage(outWith, dwInH, BufferedImage.TYPE_INT_RGB);

    for (int x = 0; x < outWith; x++) {

      int startX;
      int start;
      int theX = (int) (((double) x) * ((double) dwInW) / ((double) outWith) + 0.5);
      int theY = 0;

      startX = theX - halfDots;
      if (startX < 0) {
        startX = 0;
        start = halfDots - theX;
      } else {
        start = 0;
      }

      int stop;
      int stopX = theX + halfDots;
      if (stopX > (dwInW - 1)) {
        stopX = dwInW - 1;
        stop = halfDots + (dwInW - 1 - theX);
      } else {
        stop = halfDots * 2;
      }

      if (start > 0 || stop < dots - 1) {
        calTempContrib(start, stop);
        for (theY = 0; theY < dwInH; theY++) {
          value = horizontalFilter(bufImage, startX, stopX, start, stop, theY, tmpContrib);
          pbOut.setRGB(x, theY, value);
        }
      } else {
        for (theY = 0; theY < dwInH; theY++) {
          value = horizontalFilter(bufImage, startX, stopX, start, stop, theY, normContrib);
          pbOut.setRGB(x, theY, value);
        }
      }
    }

    return pbOut;

  } // end of horizontalFiltering()

  private int verticalFilter(BufferedImage pbInImage, int startY, int stopY, int start, int stop,
      int theX, double[] pointContrib) {
    double valueRed = 0.0;
    double valueGreen = 0.0;
    double valueBlue = 0.0;
    int valueRgb = 0;

    for (int i = startY, j = start; i <= stopY; i++, j++) {
      valueRgb = pbInImage.getRGB(theX, i);

      valueRed += getRedValue(valueRgb) * pointContrib[j];
      valueGreen += getGreenValue(valueRgb) * pointContrib[j];
      valueBlue += getBlueValue(valueRgb) * pointContrib[j];
    }

    valueRgb = comRgb(clip((int) valueRed), clip((int) valueGreen), clip((int) valueBlue));
    return valueRgb;

  }

  private BufferedImage verticalFiltering(BufferedImage pbImage, int outHeight) {
    int width = pbImage.getWidth();
    int height = pbImage.getHeight();
    int value = 0;
    BufferedImage pbOut = new BufferedImage(width, outHeight, BufferedImage.TYPE_INT_RGB);

    for (int y = 0; y < outHeight; y++) {

      int startY;
      int start;
      int theY = (int) (((double) y) * ((double) height) / ((double) outHeight) + 0.5);

      startY = theY - halfDots;
      if (startY < 0) {
        startY = 0;
        start = halfDots - theY;
      } else {
        start = 0;
      }

      int stop;
      int stopY = theY + halfDots;
      if (stopY > (int) (height - 1)) {
        stopY = height - 1;
        stop = halfDots + (height - 1 - theY);
      } else {
        stop = halfDots * 2;
      }

      if (start > 0 || stop < dots - 1) {
        calTempContrib(start, stop);
        for (int x = 0; x < width; x++) {
          value = verticalFilter(pbImage, startY, stopY, start, stop, x, tmpContrib);
          pbOut.setRGB(x, y, value);
        }
      } else {
        for (int x = 0; x < width; x++) {
          value = verticalFilter(pbImage, startY, stopY, start, stop, x, normContrib);
          pbOut.setRGB(x, y, value);
        }
      }

    }

    return pbOut;

  } // end of verticalFiltering()

  int clip(int val) {
    return (val < 0) ? 0 : (val > 255 ? 255 : val);
  }

  /**
   * shiyan图片的处理开始.
   **/
  public static boolean isImage(File file) {
    if (file == null || file.length() == 0) {
      return false;
    }
    try {
      Image img = ImageIO.read(file);
      if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) {
        return false;
      }
      return true;
    } catch (Exception ex) {
      return false;
    }
  }
  /** shiyan图片的处理结束 **/

}
